package ru.sstu.renju.javafx;

import java.util.Observable;
import java.util.Observer;
import java.util.ResourceBundle;

import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import ru.sstu.renju.config.Config;
import ru.sstu.renju.core.Game;
import ru.sstu.renju.core.Move;
import ru.sstu.renju.core.Player;
import ru.sstu.renju.javafx.renderers.FXRenderer;
import ru.sstu.renju.ui.GameRenderer;

/**
 * {@code ConfigPane} class represents main configuration pane.
 *
 * @author denis_murashev
 * @since Renju 1.1
 */
public class ConfigPane implements Observer {

	private final Config config;
	private final GridPane configPane = new GridPane();
	private final GameCanvas canvas;
	private Game game;

	private ComboBox<Player> blackPlayer;
	private ComboBox<Player> whitePlayer;
	private ComboBox<GameRenderer> renderer;
	private Text delay = new Text();
	private TextArea log = new TextArea();
	private Button playButton;

	/**
	 * Initializes panel.
	 *
	 * @param config configuration
	 * @param canvas Game canvas
	 */
	public ConfigPane(Config config, GameCanvas canvas) {
		this.config = config;
		this.canvas = canvas;
		blackPlayer = new ComboBox<Player>(FXCollections
				.observableList(config.getPlayers()));
		blackPlayer.setValue(config.getBlackPlayer());
		whitePlayer = new ComboBox<Player>(FXCollections
				.observableList(config.getPlayers()));
		whitePlayer.setValue(config.getWhitePlayer());
		renderer = new ComboBox<GameRenderer>(FXCollections
				.observableList(config.getRenderers()));
		renderer.setValue(config.getRenderer());
		final int width = 300;
		final int height = config.getGameSize() * config.getCellSize();
		configPane.setPrefSize(width, height);
		final int gap = 5;
		configPane.setHgap(gap);
		configPane.setVgap(gap);
		UIBuilder builder = new UIBuilder();
		builder.add("config.player.first", blackPlayer);
		builder.add("config.player.second", whitePlayer);
		builder.add("config.renderer", renderer);
		builder.add("config.delay", delay);
		log.setEditable(false);
		// TODO Set pretty border and fix position
//		log.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		builder.addScrollPane(log);
		playButton = new Button(config.getBundle().getString("action.play"));
		playButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				play();
			}
		});
		builder.add(playButton);
	}

	/**
	 * @return the configPane
	 */
	public GridPane getConfigPane() {
		return configPane;
	}

	@Override
	public void update(Observable o, Object arg) {
		if (game != null) {
			StringBuilder builder = new StringBuilder();
			int index = 0;
			for (Move move : game.getHistory()) {
				if (index % 2 == 0) {
					builder.append(index / 2 + 1).append(":\t");
					builder.append(move).append("\t");
				} else {
					builder.append(move).append("\n");
				}
				index++;
			}
			log.setText(builder.toString());
			// TODO scroll to the bottom
//			log.setCaretPosition(log.getText().length());
		}
	}

	/**
	 * Updating the configuration
	 */
	private void updateConfig() {
		config.setBlackPlayer(blackPlayer.getValue());
		config.setWhitePlayer(whitePlayer.getValue());
		config.setRenderer(renderer.getValue());
		try {
			config.setMoveDelay(Long.parseLong(delay.getText()));
		} catch (NumberFormatException e) {
			config.setMoveDelay(0);
		}
	}

	/**
	 * Starts playing game.
	 */
	private void play() {
		updateConfig();
		game = new Game(config);
		game.setDelay(config.getMoveDelay());
		canvas.setGame(game);
		canvas.setRenderer((FXRenderer) config.getRenderer());
		game.addObserver(this);
		new Thread(game).start();
	}

	private class UIBuilder {
		private int index = 0;

		private void add(Node node) {
			configPane.add(node, 0, index, 2, 1);
			index++;
		}

		private void add(String key, Node node) {
			ResourceBundle bundle = config.getBundle();
			configPane.add(new Label(bundle.getString(key)), 0, index);
			configPane.add(node, 1, index);
			index++;
		}

		private void addScrollPane(Node node) {
			ScrollPane scrollPane = new ScrollPane();
			scrollPane.setContent(node);
			scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
			scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
			configPane.add(scrollPane, 0, index, 2, 1);
			index++;
		}
	}
}
